// Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "shell/browser/ui/tray_icon_ohos.h"

#include <string>
#include "base/functional/bind.h"
#include "base/ohos/task_scheduler/task_runner_ohos.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/image/image_skia_rep.h"

namespace electron {

TrayIconOhos::TrayIconOhos() {
  _status_bar = std::make_unique<ohos::adapter::tray::StatusBarManager>();
}

TrayIconOhos::~TrayIconOhos() {
  _status_bar->RemoveFromStatusBar();
}

void TrayIconOhos::SetImage(const gfx::Image& image) {
  ohos::adapter::tray::TrayImage trayImage;
  ConvertSkBitmapToTrayImage(image.AsImageSkia().bitmap(), trayImage);
  auto callback = [this]() {
    auto task = base::BindOnce(
        [](TrayIconOhos* tray) {
          gfx::Rect rect;
          gfx::Point p;
          tray->NotifyClicked(rect, p, 0);
        },
        this);
    base::TaskRunnerOHOS::GetUIThreadTaskRunner()->PostTask(FROM_HERE,
                                                            std::move(task));
  };
  _status_bar->SetImage(trayImage, callback);
}

void TrayIconOhos::SetImage(const gfx::Image& white_image,
                            const gfx::Image& black_image) {
  ohos::adapter::tray::TrayImage whiteTrayImage;
  ConvertSkBitmapToTrayImage(white_image.AsImageSkia().bitmap(),
                             whiteTrayImage);
  ohos::adapter::tray::TrayImage blackTrayImage;
  ConvertSkBitmapToTrayImage(black_image.AsImageSkia().bitmap(),
                             blackTrayImage);
  auto callback = [this]() {
    auto task = base::BindOnce(
        [](TrayIconOhos* tray) {
          gfx::Rect rect;
          gfx::Point p;
          tray->NotifyClicked(rect, p, 0);
        },
        this);
    base::TaskRunnerOHOS::GetUIThreadTaskRunner()->PostTask(FROM_HERE,
                                                            std::move(task));
  };
  _status_bar->SetImage(whiteTrayImage, blackTrayImage, callback);
}

void TrayIconOhos::SetToolTip(const std::string& tool_tip) {
  _status_bar->SetToolTips(tool_tip);
}

namespace {
bool IsSubmenu(ElectronMenuModel::ItemType type) {
  if (type == ElectronMenuModel::TYPE_SUBMENU ||
      type == ElectronMenuModel::TYPE_ACTIONABLE_SUBMENU) {
    return true;
  }
  return false;
}

ElectronMenuModel* FindMenu(ElectronMenuModel* menu_model, int id) {
  if (menu_model == nullptr) {
    return nullptr;
  }
  if (menu_model->GetIndexOfCommandId(id).has_value()) {
    return menu_model;
  }
  for (size_t index = 0U; index < menu_model->GetItemCount(); ++index) {
    if (IsSubmenu(menu_model->GetTypeAt(index))) {
      ElectronMenuModel* sub_model = menu_model->GetSubmenuModelAt(index);
      if (ElectronMenuModel* model = FindMenu(sub_model, id))
        return model;
    }
  }
  return nullptr;
}
}  // namespace

void TrayIconOhos::SetContextMenu(raw_ptr<ElectronMenuModel> menu_model) {
  const std::string menu_json = menu_model->ToJsonString();
  auto callback = [menu_model](int id) {
    if (menu_model) {
      ElectronMenuModel* menu = FindMenu(menu_model, id);
      if (menu) {
        auto task = base::BindOnce([](ElectronMenuModel* menu_model,
                                      int id) { menu_model->ActivatedId(id); },
                                   menu, id);
        base::TaskRunnerOHOS::GetUIThreadTaskRunner()->PostTask(
            FROM_HERE, std::move(task));
      }
    }
  };
  _status_bar->SetContextMenu(menu_json, callback);
}

// private
void TrayIconOhos::ConvertSkBitmapToTrayImage(const SkBitmap* bitmap, ohos::adapter::tray::TrayImage& trayImage) {
  if (!bitmap->readyToDraw()) {
    return;
  }
  size_t pixelSize = bitmap->computeByteSize();
  auto pixelData(std::make_unique<char[]>(pixelSize));
  if (!bitmap->getPixels()) {
    return;
  }
  memcpy(pixelData.get(), bitmap->getPixels(), pixelSize);
  trayImage.width = bitmap->width();
  trayImage.height = bitmap->height();
  trayImage.buff = std::move(pixelData);
}

// static
TrayIcon* TrayIcon::Create(absl::optional<UUID> guid) {
  return new TrayIconOhos;
}

}  // namespace electron
